package run.core;

import java.util.ArrayList;
import java.util.List;

import run.Cell;
import run.Facet;

/**
 * Memory cell
 * May .set values
 * or .release values onto .val for exporting
 * or .init values to start off.
 * @author Thomas Chau
 *
 */
public class MEM extends Cell {

	// MEM is a state element -- this is the memory.
	private Object memory;
	private Facet set;
	private Facet release;
	private Facet val;
	private Facet init;
	private boolean onlySet;

	
	public MEM(String name) {
		super("MEM", name);
		val = new Facet(".val", this, false);
		set = new Facet(".set", this, true);
		init = new Facet(".init", this, true);
		release = new Facet(".release", this, true);
		val.addSource(set);
		
		onlySet = false;
	}
	
	/**
	 * Accept any .in and store
	 */
	@Override
	public List<Facet> stimulate(Facet stimmer) {
		
		ArrayList<Facet> doneFacets = new ArrayList<Facet>();
		
		// when receive a SET, anything not a NIL gets set as value, release.
		if (stimmer == set) {
			List<Object> incomingVals = set.dispatchOutbound();
			for (Object o : incomingVals)
				if (!(o instanceof NIL)) {
					memory = o;
					ArrayList<Object> memarr = new ArrayList<Object>();
					memarr.add(memory);
					val.receive(set, memarr);
					doneFacets.add(val);
				}
		}
		// when receive an .init, set the value inside
		else if (stimmer == init) {
			List<Object> initialValue = init.dispatchOutbound();
			if (!(initialValue.get(0) instanceof NIL)) {
				memory = initialValue.get(0);
				ArrayList<Object> memarr = new ArrayList<Object>();
				memarr.add(memory);
				val.receive(set, memarr);
				doneFacets.add(val);
			}
		}
		// when receive a .release, put out.
		else if (stimmer == release) {
			List<Object> release_hits = release.dispatchOutbound();
			Object arg = release_hits.get(0);
			ArrayList<Object> memarr = new ArrayList<Object>();
			if (!(arg instanceof NIL)) {
				memarr.add(memory);
			}
			else {
				memarr.add(arg);
			}
			val.receive(set, memarr);
			doneFacets.add(val);
		}
		
		
		return doneFacets;
	}
	
	public List<Facet> getFacets()
	{
		ArrayList<Facet> temp = new ArrayList<Facet>();
		temp.add(set);
		if(!onlySet)
		{
			temp.add(val);
		}
		temp.add(release);
		temp.add(init);
		return temp;
	}
	
	//Dot printout method
	public String toDot(String prefix)
	{
		String returnString = "";
		returnString += "subgraph " + "cluster_" + cellTypeName + hashCode() + "{\n";
		returnString += "label = \"" + cellTypeName + "\";\n";
		
		//Print my facets
		returnString += prefix + cellTypeName + hashCode() + "val [label=\".val\"];\n";
		returnString +=  prefix + cellTypeName + hashCode() + "set [label=\".set\"];\n";
		returnString += prefix + cellTypeName + hashCode() + "release [label=\".release\"];\n";
		
		returnString += "}\n";
		return returnString;
	}
}
